using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using FluentlyDo.Entities;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Linq;
using NHibernate.Type;

namespace FluentlyDo
{
    public class PersonRepository
    {
        private ISessionFactory _sessionFactory;
        private string _storedProcedureName = "GetPersonByAgeRange";

        public PersonRepository(ISessionFactory sessionFactory)
        {
            _sessionFactory = sessionFactory;
        }

        public IQueryable<Person> GetAll()
        {
            using (var session = _sessionFactory.OpenSession())
            {
                return session.Linq<Person>().ToList().AsQueryable();
            }
        }

        public Person GetById(int personId)
        {
            Person person;
            using (var session = _sessionFactory.OpenSession())
            {
                person = session.Get<Person>(personId);
            }
 
            return person;

        }

        public IList<Person> Search()
        {
            //using (var session = _sessionFactory.OpenSession())
            //{
            //    IList multiResults = session.CreateMultiCriteria()
            //        .Add(session.CreateCriteria(typeof(Person)).SetMaxResults(15))
            //        .Add(session.CreateCriteria(typeof(Person)).SetProjection(Projections.RowCount()))
            //        .List();
                
            //    IList people = (IList) multiResults[0];
            //    IList counts = (IList) multiResults[1];
            //    int count = (int) counts[0];
            //}

            using (var session = _sessionFactory.OpenSession())
            {
                var x = session.CreateMultiQuery()
                  .Add("from Person i where i.Id > 0")
                  .Add("select count(*) from Person")
                  .SetInt32("id", 50)
                  .List();

               
            }

            using (var session = _sessionFactory.OpenSession())
            {
                var count = ExecuteStoredProcedure<PersonSearch>("SearchCount", new List<Parameter>());
                var result = ExecuteStoredProcedure<PersonSearchResult>("Search", new List<Parameter>());

            }

            return new List<Person>();
        }

        public IList<Person> GetByAgeRange(int? startAge, int? endAge)
        {
            var parameters = new List<Parameter>();
            
       

            parameters.Add(new Parameter { Name = "@startAge", Type = typeof(int?), Value = startAge });
            parameters.Add(new Parameter { Name = "@endAge", Type = typeof(int?), Value = endAge });
            
            return ExecuteStoredProcedure<Person>(_storedProcedureName, parameters);
        }


        public IList<TResultEntity> ExecuteStoredProcedure<TResultEntity>
            (string storedProcedureName, IEnumerable<Parameter> parameters)
        {
            IList<TResultEntity> result;

            using (var session = _sessionFactory.OpenSession())
            {

                IQuery query = session.GetNamedQuery(storedProcedureName);
                foreach (var parameter in parameters)
                {
                   
                    if (parameter.Value == null)
                    {
                        IType type = NHibernateUtil.GuessType(parameter.Type);
                        query.SetParameter(parameter.Name, null, type);
                    }
                    else
                    {
                        query.SetParameter(parameter.Name, parameter.Value);
                    }

                }
                result = query.List<TResultEntity>();
            }
            //Execute the proc
            return result;
        }

    }

    public class Parameter
    {


        public string Name { get; set; }
        public object Value { get; set; }
        public Type Type { get; set; }

    }
}